/*
 * Copyright Aristool AG Switzerland
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */
package org.opprua.tidy.util;

/**
 * TODO: add Java doc
 * 
 * Prepared for first commit: 15.04.2007
 * 
 * @author Lin Li
 */
public class Primitives<W> {

  private static Primitives<?>[] specks = new Primitives<?>[] {
              new Primitives<Boolean>("boolean", boolean.class, "Boolean", Boolean.class,
                          "booleanValue", new Boolean(false), "false"),
              new Primitives<Byte>("byte", byte.class, "Byte", Byte.class, "byteValue", new Byte(
                          (byte) 0), "(byte) 0"),
              new Primitives<Character>("char", char.class, "Character", Character.class,
                          "charValue", new Character(' '), "' '"),
              new Primitives<Double>("double", double.class, "Double", Double.class, "doubleValue",
                          new Double(0), "0"),
              new Primitives<Float>("float", float.class, "Float", Float.class, "floatValue",
                          new Float(0), "0"),
              new Primitives<Integer>("int", int.class, "Integer", Integer.class, "intValue",
                          new Integer(0), "0"),
              new Primitives<Long>("long", long.class, "Long", Long.class, "longValue",
                          new Long(0), "0"),
              new Primitives<Short>("short", short.class, "Short", Short.class, "shortValue",
                          new Short((short) 0), "(short) 0") };

  private String typeName;
  private Class<?> typeClass;
  private String wrapperName;
  private Class<W> wrapperClass;
  private String retrieverName;
  private Object initValue;
  private String initializer;

  /**
   */
  private Primitives(String typeName, Class<?> typeClass, String wrapperName,
              Class<W> wrapperClass, String retrieverName, Object initValue, String initializer) {
    super();
    this.typeName = typeName;
    this.typeClass = typeClass;
    this.wrapperName = wrapperName;
    this.wrapperClass = wrapperClass;
    this.retrieverName = retrieverName;
    this.initializer = initializer;
    this.initValue = initValue;
  }

  /**
   * <p>
   * Find a proper Wrapper for a class. This may return null, in that case, the
   * class is a regular and does not need wrapping.
   * </p>
   * 
   * @param name
   *          of the class
   * @return the wrapper for that class (if any)
   */
  public static Primitives<?> getFor(String name) {
    for (int i = 0; i < specks.length; i++) {
      Primitives<?> s = specks[i];
      if (s.typeName.equals(name) || s.wrapperName.equals(name)
                  || s.typeClass.getName().equals(name) || s.wrapperClass.getName().equals(name)) { return s; }
    }
    return null;
  }

  /**
   * <p>
   * Find a proper primitive information for a class. This may return null, 
   * in that case, the class is a regular and does not need wrapping.
   * </p>
   * 
   * @param c
   *          the class
   * @return the wrapper for that class (if any)
   */
  public static Primitives<?> getFor(Class<?> c) {
    for (int i = 0; i < specks.length; i++) {
      Primitives<?> s = specks[i];
      if (s.typeClass.equals(c) || s.wrapperClass.equals(c)) { return s; }
    }
    return null;
  }

  /**
   * <p>
   * Find a proper Wrapper for a class. This may return null, in that case, the
   * class is a regular and does not need wrapping.
   * </p>
   * 
   * @param c
   *          the class
   * @return the wrapper for that class (if any)
   */
  public static Class<?> getWrapperFor(Class<?> c) {
    Primitives<?> p = getFor(c);
    if (p != null) {
      return p.getWrapperClass();
    }
    return c;
  }

  /**
   * <p>
   * Create an expression that turns the value of an object into something that
   * is assignable to a primitive type. For example <tt>toValue("int", "x")</tt>
   * returns <tt>((Integer)x).intValue()</tt>.
   * <p>
   * 
   * @param type
   *          a primitive type name
   * @param wrapper
   *          the name of an variable that is a wrapper of the primitive
   * @return the code fragment to turn the object into the primitive
   */
  public static String toValue(String type, String wrapper) {
    Primitives<?> s = getFor(type);
    if (s == null) { return "(" + type + ")" + wrapper; }
    return "((" + s.wrapperName + ") " + wrapper + ")" + "." + s.retrieverName + "()";
  }

  /**
   * <p>
   * Create an expression that turns the value of a primitive type into its
   * wrapper object. For example <tt>objectify("int", "x")</tt> returns
   * <tt>new Integer(x)</tt>.
   * <p>
   * 
   * @param type
   *          a primitive type of wrapper class name
   * @param value
   *          the name of an variable that is of a primitive type
   * @return the code fragment create the wrapper object for the primitive
   */
  public static String objectify(String type, String value) {
    Primitives<?> s = getFor(type);
    if (s == null) { return value; }
    return "new " + s.wrapperName + "(" + value + ")";
  }

  /**
   * <p>
   * Get the initialization value as object. For example <tt>getInitValue()</tt>
   * in an int Wrapper returns <tt>new Integer(0)</tt>.
   * </p>
   * 
   * @return initial value object of this type
   */
  public Object getInitValue() {
    return initValue;
  }

  /**
   * <p>
   * Get the name of the method from the wrapper class that returns the
   * primitive value.
   * </p>
   * 
   * @return name of the method
   */
  public String getRetrieverName() {
    return retrieverName;
  }

  /**
   * <p>
   * Get the type class of the primitive
   * </p>
   * 
   * @return the type class of the primitive
   */
  public Class<?> getTypeClass() {
    return typeClass;
  }

  /**
   * <p>
   * Get the type name of the primitive class
   * </p>
   * 
   * @return type name of the primitive
   */
  public String getTypeName() {
    return typeName;
  }

  /**
   * <p>
   * Get the class of the wrapper.
   * </p>
   * 
   * @return class of the wrapper
   */
  public Class<W> getWrapperClass() {
    return wrapperClass;
  }

  /**
   * <p>
   * Get class name of the wrapper.
   * </p>
   * 
   * @return class name of the wrapper
   */
  public String getWrapperName() {
    return wrapperName;
  }

  /**
   * <p>
   * Get the expression for the initial value of a primitive type.For example
   * <tt>getInitValue()</tt> in an int Wrapper returns <tt>"0"</tt>.
   * </p>
   * 
   * @return expression for initial value of this type
   */
  public String getInitializer() {
    return initializer;
  }
}
